'use strict';

const Controller = require('egg').Controller;
const qiniu = require('qiniu');
const fs = require('fs');
const path = require('path');

class UploadController extends Controller {

  /**
   * 获取七牛云上传token
   * GET /api/upload/token
   */
  async getToken() {
    const { ctx, app } = this;

    try {
      const qiniuConfig = app.config.qiniu;

      // 配置七牛云
      const mac = new qiniu.auth.digest.Mac(qiniuConfig.accessKey, qiniuConfig.secretKey);
      const options = {
        scope: qiniuConfig.bucket,
      };
      const putPolicy = new qiniu.rs.PutPolicy(options);
      const uploadToken = putPolicy.uploadToken(mac);

      ctx.body = {
        code: 0,
        data: {
          token: uploadToken,
          domain: qiniuConfig.domain,
          bucket: qiniuConfig.bucket,
        },
        msg: '获取token成功',
      };
    } catch (error) {
      ctx.logger.error('获取七牛云token失败:', error);
      ctx.body = {
        code: 1,
        msg: '获取token失败: ' + error.message,
        data: null,
      };
    }
  }

  /**
   * 七牛云文件上传（使用Egg.js原生方式）
   * POST /api/upload
   * @param {File} file - 上传的文件
   */
  async upload() {
    const { ctx, app } = this;

    try {
      ctx.logger.info('开始处理上传请求');

      // 使用 Egg.js 的 getFileStream 获取文件流
      const stream = await ctx.getFileStream();

      if (!stream) {
        return ctx.body = {
          code: 1,
          msg: '没有上传文件',
          data: null,
        };
      }

      ctx.logger.info('接收到文件:', {
        filename: stream.filename,
        encoding: stream.encoding,
        mime: stream.mime,
      });

      const qiniuConfig = app.config.qiniu;

      // 生成唯一文件名
      const ext = path.extname(stream.filename);
      const filename = `${Date.now()}_${Math.random().toString(36).substr(2, 9)}${ext}`;

      ctx.logger.info('开始上传文件到七牛云:', filename);

      // 配置七牛云
      const mac = new qiniu.auth.digest.Mac(qiniuConfig.accessKey, qiniuConfig.secretKey);
      const options = {
        scope: qiniuConfig.bucket,
      };
      const putPolicy = new qiniu.rs.PutPolicy(options);
      const uploadToken = putPolicy.uploadToken(mac);

      const config = new qiniu.conf.Config();
      const formUploader = new qiniu.form_up.FormUploader(config);
      const putExtra = new qiniu.form_up.PutExtra();

      // 直接使用流上传
      const uploadResult = await new Promise((resolve, reject) => {
        formUploader.putStream(uploadToken, filename, stream, putExtra, (respErr, respBody, respInfo) => {
          if (respErr) {
            ctx.logger.error('七牛云上传错误:', respErr);
            reject(new Error('上传失败: ' + respErr.message));
            return;
          }

          if (respInfo.statusCode === 200) {
            const fileUrl = `${qiniuConfig.domain}/${respBody.key}`;
            ctx.logger.info('上传成功:', fileUrl);
            resolve({
              url: fileUrl,
              filename: respBody.key,
              originalName: stream.filename,
              hash: respBody.hash,
            });
          } else {
            ctx.logger.error('七牛云响应错误:', respInfo.statusCode, respBody);
            reject(new Error('上传失败: ' + respInfo.statusCode));
          }
        });
      });

      // 返回成功响应
      ctx.body = {
        code: 0,
        msg: '上传成功',
        data: uploadResult,
      };

    } catch (error) {
      ctx.logger.error('七牛云上传错误:', error);
      ctx.body = {
        code: 1,
        msg: '上传失败: ' + error.message,
        data: null,
      };
    }
  }

  /**
   * 批量上传（使用临时文件方式）
   * POST /api/upload/batch
   * @param {Array<File>} files - 上传的文件数组
   */
  async batchUpload() {
    const { ctx, app } = this;

    try {
      ctx.logger.info('开始处理批量上传请求');

      // 获取所有上传的文件（使用 file mode）
      const parts = ctx.multipart();
      const files = [];
      let part;

      // 收集所有文件
      while ((part = await parts()) != null) {
        if (part.length) {
          // 这是字段
          ctx.logger.info('字段:', part);
        } else {
          // 这是文件流
          if (!part.filename) {
            break;
          }

          // 保存到临时文件
          const tmpFilename = `${Date.now()}_${Math.random().toString(36).substr(2, 9)}${path.extname(part.filename)}`;
          const tmpFilePath = path.join(app.config.multipart.tmpdir, tmpFilename);

          const writeStream = fs.createWriteStream(tmpFilePath);
          await new Promise((resolve, reject) => {
            part.pipe(writeStream);
            part.on('end', resolve);
            part.on('error', reject);
          });

          files.push({
            filepath: tmpFilePath,
            filename: part.filename,
            mime: part.mime,
          });
        }
      }

      if (files.length === 0) {
        return ctx.body = {
          code: 1,
          msg: '没有上传文件',
          data: null,
        };
      }

      ctx.logger.info(`接收到 ${files.length} 个文件`);

      const qiniuConfig = app.config.qiniu;

      // 上传所有文件
      const uploadPromises = files.map(async file => {
        try {
          return await this._uploadFileToQiniu(file, qiniuConfig);
        } catch (error) {
          ctx.logger.error(`文件 ${file.filename} 上传失败:`, error);
          return {
            originalName: file.filename,
            error: error.message,
          };
        } finally {
          // 删除临时文件
          try {
            fs.unlinkSync(file.filepath);
          } catch (e) {
            ctx.logger.error('删除临时文件失败:', e);
          }
        }
      });

      const results = await Promise.all(uploadPromises);

      // 统计成功和失败的数量
      const successCount = results.filter(r => !r.error).length;
      const failCount = results.length - successCount;

      ctx.body = {
        code: 0,
        msg: `上传完成，成功 ${successCount} 个，失败 ${failCount} 个`,
        data: {
          total: results.length,
          success: successCount,
          fail: failCount,
          results,
        },
      };

    } catch (error) {
      ctx.logger.error('批量上传错误:', error);
      ctx.body = {
        code: 1,
        msg: '批量上传失败: ' + error.message,
        data: null,
      };
    }
  }

  /**
   * 内部方法：上传文件到七牛云
   * @param {Object} file - 文件对象
   * @param {Object} qiniuConfig - 七牛云配置
   * @return {Promise<Object>} 上传结果
   */
  async _uploadFileToQiniu(file, qiniuConfig) {
    const ext = path.extname(file.filename);
    const filename = `${Date.now()}_${Math.random().toString(36).substr(2, 9)}${ext}`;

    // 配置七牛云
    const mac = new qiniu.auth.digest.Mac(qiniuConfig.accessKey, qiniuConfig.secretKey);
    const options = {
      scope: qiniuConfig.bucket,
    };
    const putPolicy = new qiniu.rs.PutPolicy(options);
    const uploadToken = putPolicy.uploadToken(mac);

    const config = new qiniu.conf.Config();
    const formUploader = new qiniu.form_up.FormUploader(config);
    const putExtra = new qiniu.form_up.PutExtra();

    // 上传文件
    return new Promise((resolve, reject) => {
      formUploader.putFile(uploadToken, filename, file.filepath, putExtra, (respErr, respBody, respInfo) => {
        if (respErr) {
          reject(new Error('上传失败: ' + respErr.message));
          return;
        }

        if (respInfo.statusCode === 200) {
          const fileUrl = `${qiniuConfig.domain}/${respBody.key}`;
          resolve({
            url: fileUrl,
            filename: respBody.key,
            originalName: file.filename,
            hash: respBody.hash,
          });
        } else {
          reject(new Error('上传失败: ' + respInfo.statusCode));
        }
      });
    });
  }
}

module.exports = UploadController;


